package com.atguigu.jinx.service.impl;

import cn.hutool.core.lang.Assert;
import com.atguigu.jinx.conf.JwtService;
import com.atguigu.jinx.entity.dto.JobTask;
import com.atguigu.jinx.entity.dto.User;
import com.atguigu.jinx.entity.dto.UserBalance;
import com.atguigu.jinx.entity.vo.*;
import com.atguigu.jinx.enums.SmsTemplateStatus;
import com.atguigu.jinx.exception.BusinessException;
import com.atguigu.jinx.mapper.JobTaskMapper;
import com.atguigu.jinx.mapper.UserBalanceMapper;
import com.atguigu.jinx.mapper.UserMapper;
import com.atguigu.jinx.service.IJobTaskService;
import com.atguigu.jinx.utils.NameConstants;
import com.atguigu.jinx.utils.PageUtils;
import com.atguigu.jinx.utils.TwilioSmsSender;
import com.atguigu.jinx.utils.transfer.CommonMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.mail.MessagingException;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.atguigu.jinx.enums.JobStatus.*;
import static com.atguigu.jinx.enums.SmsTemplateStatus.FORGET_TEMPLATE;
import static com.atguigu.jinx.enums.SmsTemplateStatus.LOGIN_TEMPLATE;
import static com.atguigu.jinx.utils.NameConstants.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author steve
 * @since 2025-08-07
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class JobTaskServiceImpl extends ServiceImpl<JobTaskMapper, JobTask> implements IJobTaskService {

    private final JobTaskMapper jobTaskMapper;

    private final TwilioSmsSender twilioSmsSender;

    private final RedisTemplate redisTemplate;

    private final UserMapper userMapper;

    private final JwtService jwtService;

    private final MailService mailService;

    private final UserBalanceMapper userBalanceMapper;

    /**
     * 会员可以申请的最大任务数量
     */
    @Value("${vip-max-task}")
    private int maxTask;

    @Value("${send-email-address}")
    private String sendEmailAddress;


    /**
     * portal的工作展示 9个九宫图
     *
     * @return 九个的工作
     */
    @Override
    public List<PortalJobListVO> getPortalJobListVO() {
        // 查询出任务单中未逻辑删除,排序方式为工资由高到底,限制九条
        return jobTaskMapper.selectPortalJobs();

    }

    /**
     * 验证码动态发送
     *
     * @param phoneNum 手机账号
     * @return 发送结果
     */
    @Override
    public boolean sendPhoneDynamicCode(String phoneNum, SmsTemplateStatus smsTemplateStatus) {
        // 生成6位随机验证码
        String code = TwilioSmsSender.generateRandomCode(6);

        // 动态码发送到twilio
        boolean isSent = twilioSmsSender.sendSms(phoneNum, code, smsTemplateStatus.getContent());
        // 发送成功
        if (!isSent) {
            return false;
        }
        // 发送成功，存储验证码到 Redis
        saveCodeToRedis(phoneNum, code, smsTemplateStatus.getType());
        return true;
    }

    /**
     * 通过手机动态验证码登录
     * 返回的结果{1.是否是已经注册的用户 2.是否校验正确给token}
     *
     * @param loginPhoneVO
     * @return
     */
    @Override
    public LoginResultVO phoneDynamicCodeLogin(LoginPhoneVO loginPhoneVO) {
        // 1.redis中拿到该token
        String verifyCode = (String) redisTemplate.opsForValue().get(LOGIN_TEMPLATE.getType() + ":" + loginPhoneVO.getEmail());
        // 2. 校验验证码
        if (verifyCode == null || !verifyCode.equalsIgnoreCase(loginPhoneVO.getSmsCode())) {
            // 验证码不正确或已过期
            return new LoginResultVO(null, null, false);
        }
        // 查询该账户是否注册过
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, loginPhoneVO.getEmail()));
        if (user == null) {
            // 用户未注册
            return new LoginResultVO(false, null, true);
        }
        // 4. 用户已注册,生成UserDetails对象
        String token = jwtService.generateToken(user);

        // token放到DB中
        user.setToken(token);
        user.setTokenExpired(Boolean.FALSE);
        userMapper.updateById(user);
        // 6. 返回结果，已注册且校验通过
        return new LoginResultVO(true, token, true);

    }

    /**
     * 将用户信息添加到数据库当中
     *
     * @param userVO 用户信息
     * @return 注册结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean sendLoginInfo(UserVO userVO) {
        try {
            // 将用户信息添加到数据库当中
            User user = CommonMapper.INSTANCE.UserCreateDTO2User(userVO);
            // 密码加盐
            PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            user.setPassword(passwordEncoder.encode(user.getPassword()));
            // 插入
            int insert = userMapper.insert(user);
            // 2025/08/27 往余额表里面添加一条数据
            UserBalance userBalance = new UserBalance();
            userBalance.setUserId(user.getId());
            userBalance.setBalance(new BigDecimal(0));
            userBalanceMapper.insert(userBalance);
            return insert == 1;
        } catch (DuplicateKeyException e) {
            log.error("唯一键冲突: {}", e.getMessage());
            // 判断是否是手机号唯一索引冲突
            checkDuplicate(e, "phone", "手机号已被注册");
            checkDuplicate(e, "username", "用户名已被注册");
            checkDuplicate(e, "email", "邮箱已被注册");
            throw e;
        }
    }

    /**
     * 检查重复异常
     *
     * @param e
     * @param keyword
     * @param message
     */
    private void checkDuplicate(DuplicateKeyException e, String keyword, String message) {
        String causeMsg = e.getCause() != null ? e.getCause().getMessage() : "";
        if (causeMsg.contains(keyword)) {
            throw new BusinessException(message);
        }
    }


    /**
     * @param page
     * @param jobQueryParamVO
     * @return
     */
    @Override
    public PageUtils taskListPage(Page page, JobQueryParamVO jobQueryParamVO) {
        // 从JWT中获取用户的username
        String userName = "";
        return getPage(page, jobQueryParamVO, userName);
    }

    /**
     * @param jobId 任务的id
     * @return 任务的详情
     */
    @Override
    public JobDetailVO taskDetail(String jobId) {
        return jobTaskMapper.selectDetails(jobId, "");
    }

    @Override
    public List<String> getDistinctTitles() {
        List<String> titles = jobTaskMapper.getDistinctTitles();
        if (CollectionUtils.isEmpty(titles)) {
            return Collections.emptyList();
        }
        return titles;
    }


    @Override
    public List<String> getDistinctCities() {
        List<String> cities = jobTaskMapper.getDistinctCities();
        if (CollectionUtils.isEmpty(cities)) {
            return Collections.emptyList();
        }
        return cities;
    }

    @Override
    public CheckMemberVO checkMember(String userId) {
        User user = userMapper.selectById(userId);
        boolean isMember = user.getIsMember();
        CheckMemberVO checkMemberVO = new CheckMemberVO();
        checkMemberVO.setId(userId);
        checkMemberVO.setIsMember(isMember ? 1 : 0);
        checkMemberVO.setMessage(isMember ? APPLY_CHECK_MESSAGE : NameConstants.NOT_MEMBER_MESSAGE);
        checkMemberVO.setMembershipUrl(isMember ? "" : "https://example.com/membership");
        return checkMemberVO;
    }


    /**
     * task和会员做一个绑定
     *
     * @param applyFormVO 申请会员的类
     * @return 申请结果
     */
    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public void memberApply(ApplyFormVO applyFormVO) {
        try {
            String userName = SecurityContextHolder.getContext().getAuthentication().getName();

            // 查询一个用户
            User user = Optional.ofNullable(
                            userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userName)))
                    .orElseThrow(() -> new BusinessException(NameConstants.NOT_USER));

            // 查询该任务
            JobTask jobTask = Optional.ofNullable(
                    jobTaskMapper.selectById(applyFormVO.getJobId())
            ).orElseThrow(() -> new BusinessException(NOT_JOB));

            // 查看是否是会员
            Assert.isTrue(user.getIsMember(), NameConstants.NOT_MEMBER_MESSAGE);

            // 该任务绑定了别的会员
            Assert.isFalse(jobTask.getUserId() != null && !jobTask.getUserId().equals(user.getId()), NameConstants.OTHER_USER_BIND);

            // 该任务绑定了自己
            Assert.isFalse(jobTask.getUserId() != null && jobTask.getUserId().equals(user.getId()), NameConstants.USER_BIND);

            // 检测绑定任务数量,如果是XX个以上的话,那么就不允许绑定了
            List<JobTask> jobTasks = jobTaskMapper.selectList(new LambdaQueryWrapper<JobTask>().eq(JobTask::getUserId, user.getId()));

            if (!CollectionUtils.isEmpty(jobTasks)) {
                Assert.isTrue(jobTasks.size() <= maxTask, String.format(TOO_MUCH_JOB_APPLY, maxTask));
            }

            // 会员和任务做绑定
            jobTask.setUserId(user.getId());

            // 状态变更为申请中
            jobTask.setStatus(EXECUTING.getCode());

            // 更新
            jobTaskMapper.updateById(jobTask);

            // 给{sendEmailAddress}发送邮箱
            CompletableFuture.runAsync(() ->
                    {
                        try {
                            mailService.sendSimpleMail(sendEmailAddress,
                                    "用户接单提醒", "Hello,下列这个用户接单啦,接单的用户名称为:".concat(user.getUsername())
                                            .concat(",他的手机号为:")
                                            .concat(user.getPhone())
                                            .concat("。")
                                            .concat(",接单的详情为:")
                                            .concat(jobTask.toString())
                                            .concat("。")
                            );
                        } catch (MessagingException e) {
                            throw new BusinessException(e.getMessage());
                        }
                    }
            );
        } catch (Exception e) {
            log.error("会员绑定任务时出现异常{}", e.getMessage());
            throw e;
        }
    }

    /**
     * 详情的VIP界面
     *
     * @param jobId 任务的id
     * @return 结果
     */
    @Override
    public JobDetailVipVO taskUserDetailVip(String jobId) {

        String userName = SecurityContextHolder.getContext().getAuthentication().getName();

        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userName));

        Assert.isFalse(Objects.isNull(user), NameConstants.NOT_USER);

        // 不是会员
        Assert.isTrue(user.getIsMember(), NameConstants.NOT_MEMBER_MESSAGE);

        //查询用户已经接收到的工作订单
        JobTask jobTask = jobTaskMapper.selectDetails(jobId, user.getId().toString());

        Assert.isFalse(Objects.isNull(jobTask), NameConstants.NOT_JOB);
        Assert.isFalse(
                jobTask.getUserId() != null && !jobTask.getUserId().equals(user.getId()),
                NameConstants.NOT_OPEN_FOR_CURRENT
        );

        JobDetailVipVO jobDetailVipVO = CommonMapper.INSTANCE.jobDetailTOVIPVO(jobTask);
        jobDetailVipVO.setUserName(user.getUsername());
        return jobDetailVipVO;
    }

    /**
     * 用户的账户密码登录
     *
     * @param loginUPVO 登录用户名
     * @return 登录密码
     */
    @Override
    public LoginResultVO passWordLogin(LoginUPVO loginUPVO) {
        // 盐
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        // 查询该账户是否注册过
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, loginUPVO.getUsername()));
        if (user == null) {
            // 用户未注册
            return new LoginResultVO(false, null, true);
        }

        // 匹配密码
        boolean matches = passwordEncoder.matches(loginUPVO.getPassword(), user.getPassword());
        if (!matches) {
            return new LoginResultVO(true, null, false);
        }
        // 4. 用户已注册,生成UserDetails对象
        String token = jwtService.generateToken(user);

        // token放到DB中
        user.setToken(token);
        user.setTokenExpired(Boolean.FALSE);
        userMapper.updateById(user);
        // 6. 返回结果，已注册且校验通过
        return new LoginResultVO(true, token, true);
    }

    /**
     * 校验并发送验证码
     *
     * @param phoneNum 手机号
     * @param emailNum
     * @return 是否该用户手机注册了系统
     */
    @Override
    public boolean forgetPasswordValid(String phoneNum, String emailNum) {

        if (StringUtils.isEmpty(phoneNum) && StringUtils.isEmpty(emailNum)) {
            log.warn("用户什么都没输入");
            return false;
        }
        // 手机号码
        if (StringUtils.isNotBlank(phoneNum)) {
            User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phoneNum));
            Assert.isTrue(!Objects.isNull(user), NameConstants.NOT_USER);
            return sendPhoneDynamicCode(phoneNum, FORGET_TEMPLATE);
        }

        // 邮箱号码
        if (StringUtils.isNotBlank(emailNum)) {
            User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, emailNum));
            Assert.isTrue(!Objects.isNull(user), NameConstants.NOT_USER);
            return sendCodeIfUserExists(emailNum, FORGET_TEMPLATE);
        }
        return false;
    }


    /**
     * 检查用户是否存在并发送验证码
     *
     * @return 是否发送成功
     */
    @Override
    public boolean sendCodeIfUserExists(String emailNum, SmsTemplateStatus templateStatus) {
        // 异步发送邮箱验证码
        CompletableFuture.runAsync(() -> {
            try {
                String code = TwilioSmsSender.generateRandomCode(6);
                mailService.sendSimpleMail(emailNum, templateStatus.getContent(), MAIL_TEMPLATE_CONTEXT.concat(code));
                saveCodeToRedis(emailNum, code, templateStatus.getType());
            } catch (MessagingException e) {
                log.error("发送邮箱验证码失败: {}", emailNum, e);
            }
        });
        return true;
    }


    @Override
    public boolean checkSmsCode(LoginPhoneVO loginPhoneVO, SmsTemplateStatus forgetTemplate) {
        String verifyCode;
        if (StringUtils.isNotBlank(loginPhoneVO.getPhone())) {
            // 1.redis中拿到该token
            verifyCode = (String) redisTemplate.opsForValue().get(forgetTemplate.getType() + ":" + loginPhoneVO.getPhone());
        } else if (StringUtils.isNotBlank(loginPhoneVO.getEmail())) {
            // 1.redis中拿到该token
            verifyCode = (String) redisTemplate.opsForValue().get(forgetTemplate.getType() + ":" + loginPhoneVO.getEmail());
        } else {
            verifyCode = "";
        }
        // 2. 校验验证码
        // 验证码不正确或已过期
        return verifyCode != null && verifyCode.equalsIgnoreCase(loginPhoneVO.getSmsCode());
    }

    @Override
    public boolean resetPassword(ResetPasswordVO loginUPVO) {
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        // 重置密码
        User user;
        if (StringUtils.isNotBlank(loginUPVO.getPhone())) {
            user = userMapper.selectOne(wrapper.eq(User::getPhone, loginUPVO.getPhone()));
        } else if (StringUtils.isNotBlank(loginUPVO.getEmail())) {
            user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, loginUPVO.getEmail()));
        } else {
            return false;
        }
        if (Objects.isNull(user)) {
            return false;
        }
        // 加密
        user.setPassword(passwordEncoder.encode(loginUPVO.getPassword()));
        int i = userMapper.updateById(user);
        return 1 == i;
    }

    @Override
    public JobDetailVipVO taskJobsDetailVip(String jobId) {
        String userName = SecurityContextHolder.getContext().getAuthentication().getName();

        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userName));

        log.warn("该用户尚未注册,JOBID:{},userName:{}", jobId, userName);
        Assert.isTrue(!Objects.isNull(user), NameConstants.NOT_USER);

        log.warn("该用户不是会员,JOBID:{},userName:{}", jobId, userName);
        Assert.isTrue(user.getIsMember(), NameConstants.NOT_MEMBER_MESSAGE);

        //查询用户已经接收到的工作订单
        JobTask jobTask = jobTaskMapper.selectDetails(jobId, "");

        Assert.isTrue(jobTask.getUserId() != null && jobTask.getUserId().equals(user.getId()), NameConstants.NOT_OPEN_FOR_CURRENT);

        JobDetailVipVO jobDetailVipVO = CommonMapper.INSTANCE.jobDetailTOVIPVO(jobTask);
        jobDetailVipVO.setUserName(user.getUsername());
        return jobDetailVipVO;
    }

    @Override
    public boolean sendEmailDynamicCode(String emailNum) {
        // 邮箱号码
        if (StringUtils.isNotBlank(emailNum)) {
            User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, emailNum));
            Assert.isTrue(!Objects.isNull(user), NameConstants.NOT_USER);
            return sendCodeIfUserExists(emailNum, LOGIN_TEMPLATE);
        }
        return false;
    }

    /**
     * 接单数详情
     *
     * @return 接单详情
     */
    @Override
    public TaskNumVO taskNumPage() {
        // 先求出全部的工作
        List<JobTask> jobTasks = jobTaskMapper.selectList(null);
        TaskNumVO taskNumVO = new TaskNumVO();
        int totalSize = jobTasks.size();
        taskNumVO.setTotalTaskNum(totalSize);
        //
        int canAcceptSize = jobTasks.stream().filter(jobTask -> jobTask.getStatus() == 1).toList().size();
        taskNumVO.setAcceptingNum(canAcceptSize);

        BigDecimal total = jobTasks.stream()
                .map(JobTask::getHrBonus)              // 取出 hrBonus
                .filter(Objects::nonNull)                // 过滤掉 null，避免 NPE
                .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加

        taskNumVO.setTotalTaskMoney(total);
        taskNumVO.setCanAcceptingNum(totalSize - canAcceptSize);
        return taskNumVO;
    }


    @Override
    public SalesNumVO salesDisplay() {
        // TODO 将来分库分表的时候应该怎么做?
        List<JobTask> jobTasks = jobTaskMapper.selectList(null);

        if (CollectionUtils.isEmpty(jobTasks)) {
            return new SalesNumVO();
        }
        //页面构成
        SalesNumVO salesNumVO = new SalesNumVO();
        // 发布中数量
        int size = jobTasks.stream()
                .filter(jobTask -> jobTask.getStatus() == PUBLISHED.getCode())
                .toList().size();

        ////可接单比例
        //已结单或者正在结单的数量
        salesNumVO.setTotalAcceptedNum(jobTasks.size() - size);
        // 可接单数
        salesNumVO.setTotalRetainNum(size);

        //// 按城市销量
        List<SalesNumVO.SalesNumByCityVO> result = jobTasks.stream()
                .collect(Collectors.groupingBy(JobTask::getCity, Collectors.toList()))
                .entrySet().stream()
                .map(entry -> {
                    String city = entry.getKey();
                    List<JobTask> tasks = entry.getValue();

                    SalesNumVO.SalesNumByCityVO vo = new SalesNumVO.SalesNumByCityVO();
                    vo.setCityName(city);
                    vo.setAcceptingNum((int) tasks.stream().filter(t -> t.getStatus() == 0).count());
                    vo.setAcceptedNum((int) tasks.stream().filter(t -> t.getStatus() == 1).count());
                    return vo;
                })
                .toList();
        salesNumVO.setSalesNumByCityVOList(result);

        //// 按岗位分布
        List<SalesNumVO.SalesNumByTypeVO> jobTypeStats = jobTasks.stream()
                .collect(Collectors.groupingBy(JobTask::getJobType, Collectors.counting()))
                .entrySet().stream()
                .map(entry -> {
                    SalesNumVO.SalesNumByTypeVO vo = new SalesNumVO.SalesNumByTypeVO();
                    vo.setJobType(entry.getKey());
                    vo.setJobNum(entry.getValue().intValue());
                    return vo;
                })
                .toList();
        salesNumVO.setSalesNumByTypeVOList(jobTypeStats);
        return salesNumVO;
    }

    @Override
    public MyJobNumDisplayVO myJobDisplay() {
        String userName = SecurityContextHolder.getContext().getAuthentication().getName();
        Long userId = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userName)).getId();
        List<JobTask> jobTasks = jobTaskMapper.selectList(new LambdaQueryWrapper<JobTask>().eq(JobTask::getUserId, userId));
        MyJobNumDisplayVO vo = new MyJobNumDisplayVO();
        ////今日接单
        LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
        LocalDateTime endOfDay = LocalDate.now().plusDays(1).atStartOfDay().minusNanos(1);
        int todayJobNum = jobTasks.stream().filter(jobTask -> {
            LocalDateTime bindTime = jobTask.getBindTime();
            return bindTime != null
                    && !bindTime.isBefore(startOfDay)   // >= 今天 00:00:00
                    && !bindTime.isAfter(endOfDay);    // <= 今天 23:59:59
        }).toList().size();
        vo.setTodayJobNum(todayJobNum);
        //// 进行中
        vo.setOverJobNum(jobTasks.stream().filter(jobTask -> jobTask.getStatus() == COMPLETED.getCode()).toList().size());
        //// 已完成
        vo.setAcceptedJobNum(jobTasks.stream().filter(jobTask -> jobTask.getStatus() == EXECUTING.getCode()).toList().size());

        return vo;
    }




    @Override
    public PageUtils taskListPageByUser(Page page, JobQueryParamVO jobQueryParamVO) {
        // 从JWT中获取用户的username
        String userName = SecurityContextHolder.getContext().getAuthentication().getName();
        return getPage(page, jobQueryParamVO, userName);
    }


    private PageUtils getPage(Page page, JobQueryParamVO jobQueryParamVO, String userName) {
        // 筛选条件
        String jobType = jobQueryParamVO.getJobType();
        String city = jobQueryParamVO.getCity();
        String title = jobQueryParamVO.getTitle();
        String sortHrBonus = jobQueryParamVO.getSortHrBonus();
        String sortServiceFee = jobQueryParamVO.getSortServiceFee();
        // 2025-08-26
        String jobId = jobQueryParamVO.getJobId();

        LambdaQueryWrapper<JobTask> wrapper = new LambdaQueryWrapper<>();

        // 有用户的话传递用户
        if (StringUtils.isNotBlank(userName)) {
            // 查到userId
            User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userName));
            Assert.notNull(user, "该用户未注册");
            wrapper.eq(JobTask::getUserId, user.getId());
            wrapper.eq(JobTask::getStatus, EXECUTING.getCode());
        } else {
            // 只显示发布中
            wrapper.eq(JobTask::getStatus, PUBLISHED.getCode());
        }

        // 如果是按照订单号来查询则筛选订单号
        if (StringUtils.isNotBlank(jobId)) {
            wrapper.eq(JobTask::getId, jobId);
        }

        // 如果存在title查询条件的话则进行条件筛选
        if (StringUtils.isNotBlank(title)) {
            wrapper.like(JobTask::getTitle, title);
        }

        if (StringUtils.isNotBlank(jobType)) {
            wrapper.eq(JobTask::getJobType, jobType);
        }

        if (StringUtils.isNotBlank(city)) {
            wrapper.like(JobTask::getCity, city);
        }
        //
        if (StringUtils.isNotEmpty(sortHrBonus)) {
            boolean hrBonusAsc = sortHrBonus.equalsIgnoreCase("asc");
            if (hrBonusAsc) {
                wrapper.orderByAsc(JobTask::getHrBonus);
            } else {
                wrapper.orderByDesc(JobTask::getHrBonus);
            }
        }

        //
        if (StringUtils.isNotBlank(sortServiceFee)) {
            boolean sortServiceFeeAsc = sortServiceFee.equalsIgnoreCase("asc");
            if (sortServiceFeeAsc) {
                wrapper.orderByAsc(JobTask::getServiceFee);
            } else {
                wrapper.orderByDesc(JobTask::getServiceFee);
            }
        }


        if (StringUtils.isNotBlank(city)) {
            wrapper.like(JobTask::getCity, city);
        }

        Page<JobTask> jobTaskPage = jobTaskMapper.selectPage(page, wrapper);

        // 为null则返回空
        if (CollectionUtils.isEmpty(jobTaskPage.getRecords())) {
            return null;
        }
        PageUtils pageUtils = new PageUtils(jobTaskPage);
        // VO对象
        List<JobVO> jobVOS = CommonMapper.INSTANCE.jobTaskListToVO(jobTaskPage.getRecords());
        pageUtils.setList(jobVOS);
        return pageUtils;
    }


    /**
     * 私有方法：将验证码存储到 Redis，过期时间 3 分钟
     *
     * @param phoneNum 手机号
     * @param code     验证码
     */
    private void saveCodeToRedis(String phoneNum, String code, String type) {
        String redisKey = type + ":" + phoneNum;
        redisTemplate.opsForValue().set(redisKey, code, 3, TimeUnit.MINUTES);
    }


}
